package ir.values.users.instructions.mem;

import ir.types.datatypes.ArrayType;
import ir.types.datatypes.DataType;
import ir.types.datatypes.PointerType;
import ir.values.Value;
import ir.values.users.instructions.InstOperator;
import ir.values.users.instructions.Instruction;

import java.util.ArrayList;
import java.util.List;

public class GetElementPtrInst extends Instruction {
    private final Value pointerValue;
    private final ArrayList<Value> indexValues;
    private static PointerType generateType(Value pointerValue, ArrayList<Value> indexValues) {
        PointerType pointerValueType = (PointerType) pointerValue.getType();
        if (indexValues.size() == 1) {
            return pointerValueType;
        }
        DataType retBaseType = pointerValueType.getBaseType();
        for (int i = 1; i < indexValues.size(); i++) {
            retBaseType = ((ArrayType) retBaseType).getBaseType();
        }
        return new PointerType(retBaseType);
    }
    public GetElementPtrInst(Value pointerValue, ArrayList<Value> indexValues) {
        super(null, generateType(pointerValue, indexValues));
        this.pointerValue = pointerValue;
        this.indexValues = indexValues;
        operands.add(pointerValue);
        operands.addAll(indexValues);
    }

    public GetElementPtrInst(Value pointerValue, Value... indexValue) {
        this(pointerValue, new ArrayList<>(List.of(indexValue)));
    }
    private PointerType getPointerValueType() {
        return (PointerType) pointerValue.getType();
    }

    @Override
    public InstOperator getInstOperator() {
        return InstOperator.getelementptr;
    }

    @Override
    public String parseLLVM() {
        StringBuilder sb = new StringBuilder();
        sb
                .append(parseUsingName())
                .append(" = ")
                .append(getInstOperator())
                .append(" ")
                .append(getPointerValueType().getBaseType())
                .append(", ")
                .append(getPointerValueType())
                .append(" ")
                .append(pointerValue.parseUsingName());
        for (Value indexValue : indexValues) {
            sb
                    .append(", ")
                    .append(indexValue.getType().toString())
                    .append(" ")
                    .append(indexValue.parseUsingName());
        }
        return sb.toString();
    }

}
